package org.system.core.service.system;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import org.system.core.common.Constants;
import org.system.core.domain.entity.SysUser;
import org.system.core.domain.model.LoginUser;
import org.system.core.exception.ServiceException;
import org.system.core.exception.UserNotExistsException;
import org.system.core.exception.UserPasswordNotMatchException;
import org.system.core.manager.AsyncFactory;
import org.system.core.manager.AsyncManager;
import org.system.core.security.context.AuthenticationContextHolder;
import org.system.core.utils.DateUtils;
import org.system.core.utils.MessageUtils;
import org.system.core.utils.StringUtils;
import org.system.core.utils.ip.IpUtils;

/**
 * @author baoRoot
 */
@Service
public class SysLoginService {

    private static final Logger logger = LoggerFactory.getLogger(SysLoginService.class);

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private SysUserService sysUserService;

    public String login(String username, String password) {

        loginPreCheck(username, password);

        Authentication authentication = null;
        try{
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
            AuthenticationContextHolder.setContext(authenticationToken);

            authentication = authenticationManager.authenticate(authenticationToken);
        } catch (Exception e) {
            if (e instanceof BadCredentialsException) {
                logger.warn(e.getMessage());
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, "用户名或密码错误"));
                throw new UserPasswordNotMatchException(MessageUtils.message("system.user.password_error"));
            } else {
                logger.warn("登录用户其他错误: {}", e.getMessage());
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
                throw new ServiceException(e.getMessage());
            }
        } finally {
            AuthenticationContextHolder.clearContext();
        }
        logger.info("用户登录成功: {}", username);
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, "登录成功"));
        // todo 记录用户登录信息可以使用异步或者MQ等进行
        recordLoginInfo(loginUser.getUserId());
        return tokenService.createToken(loginUser);
    }

    private void loginPreCheck(String username, String password) {
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
            logger.warn("用户名或密码不能为空");
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, "用户名或密码不能为空"));
            throw new UserNotExistsException(MessageUtils.message("system.user.password_and_username"));
        }
        if (username.length() < Constants.USERNAME_MIN_LENGTH || username.length() > Constants.USERNAME_MAX_LENGTH) {
            logger.warn("用户名或密码错误");
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, "用户名或密码错误"));
            throw new UserPasswordNotMatchException(MessageUtils.message("system.user.password_error"));
        }
        if (password.length() < Constants.PASSWORD_MIN_LENGTH || password.length() > Constants.PASSWORD_MAX_LENGTH) {
            logger.warn("用户名或密码错误");
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, "用户名或密码错误"));
            throw new UserPasswordNotMatchException(MessageUtils.message("system.user.password_error"));
        }
    }

    public void recordLoginInfo(Long userId) {
        SysUser sysUser = new SysUser();
        sysUser.setUserId(userId);
        sysUser.setLoginIp(IpUtils.getIpAddr());
        sysUser.setLoginDate(DateUtils.getNowDate());
        sysUserService.updateUserProfile(sysUser);
    }
}
